﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Arch.Common.IoC;
using Arch.Intercep.CallHandlers;
using Arch.Intercep.Interceptors;
using Arch.Services.ErrorHandling;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;
using Arch.Data;
using Arch.Intercep;
using Microsoft.Practices.Unity.InterceptionExtension;
using IInterceptor = Arch.Intercep.IInterceptor;

namespace Arch.IoC
{
    public class ServerDependencyContainer : ArchUnityDependencyContainer
    {
        protected override void RegisterDefaults(IUnityContainer container)
        {
            base.RegisterDefaults(container);
            container.RegisterInstance<IEnumerable<IExceptionToFaultHandler>>(new IExceptionToFaultHandler[] { new ValidationExceptionToFaultHandler() });


            container.RegisterInstance<IDictionary<IInterceptor, ActionTarget>>(
                new Dictionary<IInterceptor, ActionTarget>
                    {
                        { container.Resolve<AspectInterceptor>(), ActionTarget.All },
                        { container.Resolve<ValidationInterceptor>(),  ActionTarget.Creating | ActionTarget.Updating },
                        {  container.Resolve<SecurityInterceptor>(), ActionTarget.Creating | ActionTarget.Updating | ActionTarget.Deleting | ActionTarget.Loading },
                    }
                );
            container.RegisterType<IInterceptorManager, DefaultInterceptorManager>();
        }

        public virtual void ConfigureInterception(Interception interception)
        {
            interception.AddPolicy("Create").AddCallHandler(Container.Resolve<ActionInterceptionHandler>()
                                                                .SetTargets(ActionTarget.Creating, ActionTarget.Created))
                .AddMatchingRule(new MemberNameMatchingRule("Create"));

            interception.AddPolicy("Update").AddCallHandler(Container.Resolve<ActionInterceptionHandler>()
                                                                .SetTargets(ActionTarget.Updating, ActionTarget.Updated))
                .AddMatchingRule(new MemberNameMatchingRule("Update"));

            interception.AddPolicy("Delete").AddCallHandler(Container.Resolve<ActionInterceptionHandler>()
                                                                .SetTargets(ActionTarget.Deleting, ActionTarget.Deleted))
                .AddMatchingRule(new MemberNameMatchingRule("Delete"));

            interception.AddPolicy("Load").AddCallHandler(Container.Resolve<ActionInterceptionHandler>()
                                                              .SetTargets(ActionTarget.Loading, ActionTarget.Loaded))
                .AddMatchingRule(new MemberNameMatchingRule("Load"));
            interception.AddPolicy("Find").AddCallHandler(Container.Resolve<ActionInterceptionHandler>()
                                                  .SetTargets(ActionTarget.Loading, ActionTarget.Loaded))
                .AddMatchingRule(new MemberNameMatchingRule("Find"));
        }

        public virtual void ApplyDefaultInterception(Type interfaceType, Type type)
        {
            ConfigureInterception(Container.Configure<Interception>().SetDefaultInterceptorFor(type, new VirtualMethodInterceptor()));
        }

        public virtual void ApplyEmptyInterception(Type interfaceType, Type type)
        {
            Container.Configure<Interception>().SetDefaultInterceptorFor(type, new VirtualMethodInterceptor());
        }

        protected override void AutoRegisterTypes(IUnityContainer container, Type baseInterfaceType, ICollection<Type> types, Action<Type, Type> applyConfiguration = null)
        {
            if (applyConfiguration == null) applyConfiguration = ApplyEmptyInterception;
            base.AutoRegisterTypes(container, baseInterfaceType, types, applyConfiguration);
        }

        public override void AutoRegister(IUnityContainer container)
        {
            AutoRegisterTypes(container, typeof(IRepository<>), GetLayerTypes(container, "Repository"), ApplyDefaultInterception);
            ConfigureInterception(container.Configure<Interception>().SetDefaultInterceptorFor(GetMappedType(container, "Repository"), new VirtualMethodInterceptor()));
        }

        protected override void LoadExtensions(IUnityContainer container)
        {
            base.LoadExtensions(container);
            container.AddNewExtension<Interception>();
        }
    }
}
